// crypto 模块中文API封装 - 基于Node.js内置crypto库
const crypto = require('crypto');

/**
 * 生成随机字节
 * @param {number} 大小 - 要生成的随机字节数
 * @returns {Buffer} 随机字节的Buffer
 */
function 生成随机字节(大小 = 32) {
  return crypto.randomBytes(大小);
}

/**
 * 生成随机字符串
 * @param {number} 长度 - 随机字符串长度
 * @param {string} 字符集 - 可选的字符集，默认为字母数字
 * @returns {string} 随机字符串
 */
function 生成随机字符串(长度 = 32, 字符集 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
  const 随机字节 = crypto.randomBytes(长度);
  let 结果 = '';
  
  for (let i = 0; i < 长度; i++) {
    结果 += 字符集[随机字节[i] % 字符集.length];
  }
  
  return 结果;
}

/**
 * 创建AES加密器
 * @param {string} 密钥 - 加密密钥
 * @param {string} 算法 - AES算法，如 'aes-256-cbc'
 * @param {Buffer|string} 初始化向量 - 初始化向量
 * @returns {Cipher} AES加密器
 */
function 创建AES加密器(密钥, 算法 = 'aes-256-cbc', 初始化向量) {
  return crypto.createCipheriv(算法, 密钥, 初始化向量);
}

/**
 * 创建AES解密器
 * @param {string} 密钥 - 解密密钥
 * @param {string} 算法 - AES算法，如 'aes-256-cbc'
 * @param {Buffer|string} 初始化向量 - 初始化向量
 * @returns {Decipher} AES解密器
 */
function 创建AES解密器(密钥, 算法 = 'aes-256-cbc', 初始化向量) {
  return crypto.createDecipheriv(算法, 密钥, 初始化向量);
}

/**
 * AES加密数据
 * @param {string|Buffer} 数据 - 要加密的数据
 * @param {string} 密钥 - 加密密钥
 * @param {Object} 选项 - 加密选项
 * @returns {Object} 包含加密数据和初始化向量的对象
 */
function AES加密(数据, 密钥, 选项 = {}) {
  const { 算法 = 'aes-256-cbc', 输出编码 = 'base64' } = 选项;
  const 密钥长度 = 算法.includes('256') ? 32 : (算法.includes('192') ? 24 : 16);
  
  // 确保密钥长度正确
  let 处理后的密钥 = 密钥;
  if (typeof 处理后的密钥 === 'string') {
    const 哈希 = crypto.createHash('sha256').update(处理后的密钥).digest();
    处理后的密钥 = 哈希.slice(0, 密钥长度);
  }
  
  // 生成初始化向量
  const 初始化向量 = crypto.randomBytes(16);
  
  // 创建加密器
  const 加密器 = crypto.createCipheriv(算法, 处理后的密钥, 初始化向量);
  
  // 加密数据
  let 加密数据 = 加密器.update(data);
  加密数据 = Buffer.concat([加密数据, 加密器.final()]);
  
  return {
    加密数据: 加密数据.toString(输出编码),
    初始化向量: 初始化向量.toString(输出编码)
  };
}

/**
 * AES解密数据
 * @param {string|Buffer} 加密数据 - 要解密的数据
 * @param {string} 密钥 - 解密密钥
 * @param {string|Buffer} 初始化向量 - 初始化向量
 * @param {Object} 选项 - 解密选项
 * @returns {string} 解密后的明文
 */
function AES解密(加密数据, 密钥, 初始化向量, 选项 = {}) {
  const { 算法 = 'aes-256-cbc', 输入编码 = 'base64', 输出编码 = 'utf8' } = 选项;
  const 密钥长度 = 算法.includes('256') ? 32 : (算法.includes('192') ? 24 : 16);
  
  // 确保密钥长度正确
  let 处理后的密钥 = 密钥;
  if (typeof 处理后的密钥 === 'string') {
    const 哈希 = crypto.createHash('sha256').update(处理后的密钥).digest();
    处理后的密钥 = 哈希.slice(0, 密钥长度);
  }
  
  // 转换数据格式
  const 加密Buffer = typeof 加密数据 === 'string' ? Buffer.from(加密数据, 输入编码) : 加密数据;
  const 向量Buffer = typeof 初始化向量 === 'string' ? Buffer.from(初始化向量, 输入编码) : 初始化向量;
  
  // 创建解密器
  const 解密器 = crypto.createDecipheriv(算法, 处理后的密钥, 向量Buffer);
  
  // 解密数据
  let 解密数据 = 解密器.update(加密Buffer);
  解密数据 = Buffer.concat([解密数据, 解密器.final()]);
  
  return 解密数据.toString(输出编码);
}

/**
 * 创建哈希对象
 * @param {string} 算法 - 哈希算法名称，如 'md5', 'sha256'
 * @returns {Hash} 哈希对象
 */
function 创建哈希(算法 = 'sha256') {
  return crypto.createHash(算法);
}

/**
 * 计算数据的哈希值
 * @param {string|Buffer} 数据 - 要计算哈希的数据
 * @param {string} 算法 - 哈希算法，默认'sha256'
 * @param {string} 输出编码 - 输出编码，默认'hex'
 * @returns {string} 哈希值
 */
function 计算哈希(数据, 算法 = 'sha256', 输出编码 = 'hex') {
  return crypto.createHash(算法).update(data).digest(输出编码);
}

/**
 * 计算MD5哈希
 * @param {string|Buffer} 数据 - 要计算MD5的数据
 * @param {string} 输出编码 - 输出编码，默认'hex'
 * @returns {string} MD5哈希值
 */
function 计算MD5(数据, 输出编码 = 'hex') {
  return 计算哈希(data, 'md5', 输出编码);
}

/**
 * 计算SHA1哈希
 * @param {string|Buffer} 数据 - 要计算SHA1的数据
 * @param {string} 输出编码 - 输出编码，默认'hex'
 * @returns {string} SHA1哈希值
 */
function 计算SHA1(数据, 输出编码 = 'hex') {
  return 计算哈希(data, 'sha1', 输出编码);
}

/**
 * 计算SHA256哈希
 * @param {string|Buffer} 数据 - 要计算SHA256的数据
 * @param {string} 输出编码 - 输出编码，默认'hex'
 * @returns {string} SHA256哈希值
 */
function 计算SHA256(数据, 输出编码 = 'hex') {
  return 计算哈希(data, 'sha256', 输出编码);
}

/**
 * 创建HMAC对象
 * @param {string} 算法 - HMAC算法名称
 * @param {string|Buffer} 密钥 - HMAC密钥
 * @returns {Hmac} HMAC对象
 */
function 创建HMAC(算法 = 'sha256', 密钥) {
  return crypto.createHmac(算法, 密钥);
}

/**
 * 计算HMAC值
 * @param {string|Buffer} 数据 - 要计算HMAC的数据
 * @param {string|Buffer} 密钥 - HMAC密钥
 * @param {string} 算法 - HMAC算法，默认'sha256'
 * @param {string} 输出编码 - 输出编码，默认'hex'
 * @returns {string} HMAC值
 */
function 计算HMAC(数据, 密钥, 算法 = 'sha256', 输出编码 = 'hex') {
  return crypto.createHmac(算法, 密钥).update(data).digest(输出编码);
}

/**
 * 生成密钥对
 * @param {string} 算法 - 密钥算法，如 'rsa'
 * @param {Object} 选项 - 密钥生成选项
 * @returns {Object} 包含公钥和私钥的对象
 */
function 生成密钥对(算法 = 'rsa', 选项 = {}) {
  const { 模数长度 = 2048, 公共指数 = 0x10001 } = 选项;
  
  return new Promise((resolve, reject) => {
    crypto.generateKeyPair(算法, {
      modulusLength: 模数长度,
      publicExponent: 公共指数,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
        ...(选项.私钥密码 ? { cipher: 'aes-256-cbc', passphrase: 选项.私钥密码 } : {})
      }
    }, (错误, 公钥, 私钥) => {
      if (错误) {
        reject(错误);
      } else {
        resolve({ 公钥, 私钥 });
      }
    });
  });
}

/**
 * 创建数字签名
 * @param {string|Buffer} 数据 - 要签名的数据
 * @param {string|Buffer} 私钥 - 签名私钥
 * @param {Object} 选项 - 签名选项
 * @returns {string} 签名字符串
 */
function 创建数字签名(数据, 私钥, 选项 = {}) {
  const { 算法 = 'sha256', 输出编码 = 'base64', 私钥密码 } = 选项;
  
  const 签名器 = crypto.createSign(算法);
  签名器.update(data);
  
  const 私钥选项 = 私钥密码 ? { passphrase: 私钥密码 } : {};
  return 签名器.sign(私钥, 私钥选项).toString(输出编码);
}

/**
 * 验证数字签名
 * @param {string|Buffer} 数据 - 要验证的数据
 * @param {string} 签名 - 签名字符串
 * @param {string|Buffer} 公钥 - 验证公钥
 * @param {Object} 选项 - 验证选项
 * @returns {boolean} 签名是否有效
 */
function 验证数字签名(数据, 签名, 公钥, 选项 = {}) {
  const { 算法 = 'sha256', 输入编码 = 'base64' } = 选项;
  
  const 验证器 = crypto.createVerify(算法);
  验证器.update(data);
  
  return 验证器.verify(公钥, Buffer.from(签名, 输入编码));
}

/**
 * 创建密码派生函数
 * @param {string} 密码 - 原始密码
 * @param {Object} 选项 - 派生选项
 * @returns {Buffer} 派生的密钥
 */
function 派生密钥(密码, 选项 = {}) {
  const { 
    算法 = 'sha256', 
    盐 = crypto.randomBytes(16), 
    迭代次数 = 100000, 
    密钥长度 = 32 
  } = 选项;
  
  return crypto.pbkdf2Sync(密码, 盐, 迭代次数, 密钥长度, 算法);
}

/**
 * 异步派生密钥
 * @param {string} 密码 - 原始密码
 * @param {Object} 选项 - 派生选项
 * @returns {Promise<Object>} 包含派生密钥和盐的对象
 */
async function 异步派生密钥(密码, 选项 = {}) {
  const { 
    算法 = 'sha256', 
    盐 = crypto.randomBytes(16), 
    迭代次数 = 100000, 
    密钥长度 = 32 
  } = 选项;
  
  return new Promise((resolve, reject) => {
    crypto.pbkdf2(密码, 盐, 迭代次数, 密钥长度, 算法, (错误, 派生密钥) => {
      if (错误) {
        reject(错误);
      } else {
        resolve({ 密钥: 派生密钥, 盐 });
      }
    });
  });
}

/**
 * 加密密码（带盐值）
 * @param {string} 密码 - 原始密码
 * @param {Object} 选项 - 加密选项
 * @returns {string} 加密后的密码字符串
 */
function 加密密码(密码, 选项 = {}) {
  const { 算法 = 'sha256', 迭代次数 = 100000 } = 选项;
  
  // 生成随机盐值
  const 盐 = crypto.randomBytes(16).toString('hex');
  
  // 派生密钥
  const 派生密钥 = crypto.pbkdf2Sync(密码, 盐, 迭代次数, 64, 算法).toString('hex');
  
  // 返回格式：算法$迭代次数$盐值$派生密钥
  return `${算法}$${迭代次数}$${盐}$${派生密钥}`;
}

/**
 * 验证密码
 * @param {string} 密码 - 要验证的原始密码
 * @param {string} 哈希密码 - 加密后的密码字符串
 * @returns {boolean} 密码是否匹配
 */
function 验证密码(密码, 哈希密码) {
  try {
    // 解析哈希密码字符串
    const [算法, 迭代次数, 盐, 存储的密钥] = 哈希密码.split('$');
    
    // 用相同参数派生密钥
    const 派生密钥 = crypto.pbkdf2Sync(
      密码, 
      盐, 
      parseInt(迭代次数, 10), 
      64, 
      算法
    ).toString('hex');
    
    // 比较密钥
    return 派生密钥 === 存储的密钥;
  } catch (错误) {
    console.error('密码验证出错:', 错误);
    return false;
  }
}

/**
 * 创建Diffie-Hellman密钥交换对象
 * @param {number} 模数长度 - 模数长度
 * @returns {DiffieHellman} DH对象
 */
function 创建DiffieHellman(模数长度 = 2048) {
  return crypto.createDiffieHellman(模数长度);
}

/**
 * 创建密钥交换对象（使用预定义模数）
 * @param {Buffer} 质数 - 质数模数
 * @param {Buffer} 生成器 - 生成器
 * @returns {DiffieHellman} DH对象
 */
function 创建DiffieHellmanWithParams(质数, 生成器 = Buffer.from([2])) {
  return crypto.createDiffieHellman(质数, 生成器);
}

/**
 * 执行Diffie-Hellman密钥交换
 * @param {Object} 配置 - 密钥交换配置
 * @returns {Object} 交换结果
 */
async function 执行密钥交换(配置 = {}) {
  const { 模数长度 = 2048 } = 配置;
  
  // 创建两个DH实例
  const 方A = crypto.createDiffieHellman(模数长度);
  const 方A密钥 = 方A.generateKeys();
  
  const 方B = crypto.createDiffieHellman(方A.getPrime(), 方A.getGenerator());
  const 方B密钥 = 方B.generateKeys();
  
  // 计算共享密钥
  const 方A共享密钥 = 方A.computeSecret(方B密钥);
  const 方B共享密钥 = 方B.computeSecret(方A密钥);
  
  return {
    方A: {
      公钥: 方A密钥,
      共享密钥: 方A共享密钥
    },
    方B: {
      公钥: 方B密钥,
      共享密钥: 方B共享密钥
    },
    共享密钥匹配: 方A共享密钥.equals(方B共享密钥)
  };
}

/**
 * 生成UUID v4
 * @returns {string} UUID字符串
 */
function 生成UUID() {
  return crypto.randomUUID();
}

/**
 * 加密字符串（简化版本）
 * @param {string} 明文 - 要加密的明文字符串
 * @param {string} 密钥 - 加密密钥
 * @returns {string} 加密后的字符串
 */
function 加密字符串(明文, 密钥) {
  const 密钥哈希 = crypto.createHash('sha256').update(密钥).digest();
  const 初始化向量 = crypto.randomBytes(16);
  
  const 加密器 = crypto.createCipheriv('aes-256-cbc', 密钥哈希, 初始化向量);
  let 加密数据 = 加密器.update(明文, 'utf8', 'base64');
  加密数据 += 加密器.final('base64');
  
  return 初始化向量.toString('base64') + ':' + 加密数据;
}

/**
 * 解密字符串（简化版本）
 * @param {string} 加密字符串 - 要解密的字符串
 * @param {string} 密钥 - 解密密钥
 * @returns {string} 解密后的明文字符串
 */
function 解密字符串(加密字符串, 密钥) {
  const [初始化向量Base64, 加密数据] = 加密字符串.split(':');
  const 密钥哈希 = crypto.createHash('sha256').update(密钥).digest();
  const 初始化向量 = Buffer.from(初始化向量Base64, 'base64');
  
  const 解密器 = crypto.createDecipheriv('aes-256-cbc', 密钥哈希, 初始化向量);
  let 解密数据 = 解密器.update(加密数据, 'base64', 'utf8');
  解密数据 += 解密器.final('utf8');
  
  return 解密数据;
}

/**
 * 计算文件哈希
 * @param {string} 文件路径 - 文件路径
 * @param {string} 算法 - 哈希算法
 * @returns {Promise<string>} 文件哈希值
 */
async function 计算文件哈希(文件路径, 算法 = 'sha256') {
  const fs = require('fs');
  
  return new Promise((resolve, reject) => {
    try {
      const 哈希 = crypto.createHash(算法);
      const 读取流 = fs.createReadStream(文件路径);
      
      读取流.on('error', 错误 => {
        reject(new Error(`读取文件时出错: ${错误.message}`));
      });
      
      读取流.on('data', 数据 => {
        哈希.update(数据);
      });
      
      读取流.on('end', () => {
        resolve(哈希.digest('hex'));
      });
    } catch (错误) {
      reject(错误);
    }
  });
}

/**
 * 生成临时令牌
 * @param {number} 长度 - 令牌长度
 * @returns {string} 临时令牌
 */
function 生成临时令牌(长度 = 32) {
  return crypto.randomBytes(Math.ceil(长度 / 2)).toString('hex').slice(0, 长度);
}

/**
 * 检查算法是否支持
 * @param {string} 算法 - 算法名称
 * @param {string} 类型 - 算法类型: 'digest', 'cipher', 'hash', 'sign'
 * @returns {boolean} 是否支持该算法
 */
function 检查算法支持(算法, 类型 = 'digest') {
  try {
    switch (类型) {
      case 'digest':
        return crypto.getHashes().includes(算法);
      case 'cipher':
        return crypto.getCiphers().includes(算法);
      case 'hash':
        return crypto.getHashes().includes(算法);
      case 'sign':
        return crypto.getHashes().includes(算法);
      default:
        return false;
    }
  } catch (错误) {
    return false;
  }
}

// 导出API
module.exports = {
  // 随机数生成
  生成随机字节,
  生成随机字符串,
  生成UUID,
  生成临时令牌,
  
  // 哈希函数
  创建哈希,
  计算哈希,
  计算MD5,
  计算SHA1,
  计算SHA256,
  计算文件哈希,
  
  // HMAC
  创建HMAC,
  计算HMAC,
  
  // AES加密解密
  创建AES加密器,
  创建AES解密器,
  AES加密,
  AES解密,
  加密字符串,
  解密字符串,
  
  // 密钥管理
  生成密钥对,
  派生密钥,
  异步派生密钥,
  加密密码,
  验证密码,
  
  // 数字签名
  创建数字签名,
  验证数字签名,
  
  // 密钥交换
  创建DiffieHellman,
  创建DiffieHellmanWithParams,
  执行密钥交换,
  
  // 工具函数
  检查算法支持,
  
  // 获取原始库引用
  获取原始Crypto: () => crypto
};
